﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Saxon.Api;
using System.Xml.Linq;
using System.Collections;
using System.Xml;
using net.sf.saxon.dotnet;
using net.sf.saxon.value;
using net.sf.saxon.om;
using WMM.Tapioca.Utilities;

namespace WMM.Tapioca.Formula.Functions
{
    //xfi:precision($item as schema-element(xbrli:item)) as xdt:anyAtomicType
    //Parameters
    //$item
    //The item for which to obtain the precision.
    //Return the actual or the inferred precision of a numeric fact.

    //For non‑numeric facts, the dynamic error xfie:ItemIsNotNumeric occurs.

    public class PrecisionXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "precision"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_INTEGER), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new PrecisionXfiCall();
        }
    }

    public class PrecisionXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string precision = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode item = (XdmNode)arguments[0].Current;

                IEnumerator attrs = item.EnumerateAxis(XdmAxis.Attribute, new QName("precision"));

                while (attrs.MoveNext())
                {
                    XdmNode attr = (XdmNode)attrs.Current;

                    precision = attr.StringValue;
                }

                if (precision == null)
                {
                    throw new XfiException("xfie:ItemIsNotNumeric");
                }

                XdmAtomicValue result = new XdmAtomicValue(precision);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    // ===================================== Contexts and units ==================================================

    //xfi:context($item as schema-element(xbrli:item)) as element(xbrli:context)
    //Parameters
    //$item
    //The item for which to obtain the context.
    //Return the context whose id attribute value is equal to the item’s contextRef attribute value.

    public class ContextXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "context"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ContextXfiCall();
        }
    }

    public class ContextXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode contextNode = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode item = (XdmNode)arguments[0].Current;

                IEnumerator attributes = item.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;
                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator contexts = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;

                    IEnumerator attrs = currentContext.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                contextNode = currentContext;
                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)contextNode.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:unit($item as schema-element(xbrli:item)) as element(xbrli:unit)?
    //Parameters
    //$item
    //The item for which to obtain the unit.
    //Returns the unit whose id attribute value is equal to the item’s unitRef attribute value.  For non-numeric items the empty sequence is returned.

    public class UnitXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "unit"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new UnitXfiCall();
        }
    }

    public class UnitXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode unit = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string unitRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;
                        if (attributeName.Equals("unitRef"))
                        {
                            unitRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator units = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "unit"));

                while (units.MoveNext())
                {
                    XdmNode item = (XdmNode)units.Current;

                    IEnumerator attrs = item.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == unitRef)
                            {
                                IEnumerator unitElements = item.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "unit"));

                                while (unitElements.MoveNext())
                                {
                                    unit = (XdmNode)unitElements.Current;
                                    break;
                                }

                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)unit.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:unit-numerator($unit as element(xbrli:unit)) as element(xbrli:measure)+
    //Parameters
    //$item
    //The unit for which to obtain the numerator.
    //Returns either the measure elements that occur as children of the unitNumerator descendant of the unit in the case where a divide element occurs;
    //otherwise returns the measure children of the unit.

    public class UnitNumeratorXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "unit-numerator"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new UnitNumeratorXfiCall();
        }
    }

    public class UnitNumeratorXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode measure = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode unit = (XdmNode)arguments[0].Current;

                IEnumerator measures = unit.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "measure"));

                while (measures.MoveNext())
                {
                    measure = (XdmNode)measures.Current;
                    return (IXdmEnumerator)measure.GetEnumerator();
                }

                IEnumerator divides = unit.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "divide"));

                XdmNode divide = new XdmNode();

                while (divides.MoveNext())
                {
                    divide = (XdmNode)divides.Current;

                    IEnumerator unitNumerator = divide.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "unitNumerator"));

                    while (unitNumerator.MoveNext())
                    {
                        measures = ((XdmNode)unitNumerator.Current).EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "measure"));

                        while (measures.MoveNext())
                        {
                            measure = (XdmNode)measures.Current;
                        }
                    }
                }

                IXdmEnumerator result = (IXdmEnumerator)measure.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:unit-denominator($unit as element(xbrli:unit)) as element(xbrli:measure)*
    //Parameters
    //$item
    //The unit for which to obtain the denominator.
    //Returns either the measure elements that occur as children of the unitDenominator descendant of the unit in the 
    //case where a divide element occurs; otherwise returns an empty list.

    public class UnitDenominatorXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "unit-denominator"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new UnitDenominatorXfiCall();
        }
    }

    public class UnitDenominatorXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode measure = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode unit = (XdmNode)arguments[0].Current;

                IEnumerator measures = unit.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "measure"));

                while (measures.MoveNext())
                {
                    measure = (XdmNode)measures.Current;
                    return (IXdmEnumerator)measure.GetEnumerator();
                }

                IEnumerator divides = unit.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "divide"));

                XdmNode divide = new XdmNode();

                while (divides.MoveNext())
                {
                    divide = (XdmNode)divides.Current;

                    IEnumerator unitDenominator = divide.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "unitDenominator"));

                    while (unitDenominator.MoveNext())
                    {
                        measures = ((XdmNode)unitDenominator.Current).EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "measure"));

                        while (measures.MoveNext())
                        {
                            measure = (XdmNode)measures.Current;
                        }
                    }
                }

                IXdmEnumerator result = (IXdmEnumerator)measure.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    public class MeasureNameXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "measure-name"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_QNAME), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new MeasureNameXfiCall();
        }
    }

    public class MeasureNameXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string measureValue = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode measure = (XdmNode)arguments[0].Current;

                measureValue = measure.StringValue;

                XdmAtomicValue result = new XdmAtomicValue(measureValue);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    // ====================== Contexts ==============================================

    //xfi:period($item as schema-element(xbrli:item)) as element(xbrli:period)
    //Parameters
    //$item
    //The item.
    //Return the period element of the context matching the supplied item’s contextRef attribute.

    public class PeriodXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "period"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new PeriodXfiCall();
        }
    }

    public class PeriodXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode period = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;

                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                } 

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator contexts = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI,"context"));

                while (contexts.MoveNext())
                {
                    XdmNode item = (XdmNode)contexts.Current;
                    
                    IEnumerator attrs = item.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                IEnumerator periodElements = item.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "period"));

                                while (periodElements.MoveNext())
                                {
                                    period = (XdmNode)periodElements.Current;
                                    break;                                    
                                }

                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)period.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:context-period($context as element(xbrli:context)) as element(xbrli:period)
    //Parameters
    //$context
    // The context.
    //Return the period element of the supplied context.

    public class ContextPeriodXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "context-period"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ContextPeriodXfiCall();
        }
    }

    public class ContextPeriodXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode period = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode contextNode = (XdmNode)arguments[0].Current;

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator periods = contextNode.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "period"));

                while (periods.MoveNext())
                {
                    period = (XdmNode)periods.Current;
                    break;
                }

                IXdmEnumerator result = (IXdmEnumerator)period.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:is-start-end-period($period as element(xbrli:period)) as xs:boolean
    //Parameters
    //$period
    //The period.
    //Return true if the period contains a startDate and endDate style period and false otherwise.

    public class IsStartEndPeriodXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "is-start-end-period"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IsStartEndPeriodXfiCall();
        }
    }

    public class IsStartEndPeriodXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            bool isStartEndPeriod = false;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode period = (XdmNode)arguments[0].Current;

                IEnumerator startDate = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "startDate"));

                IEnumerator endDate = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "endDate"));

                if (startDate.MoveNext() && endDate.MoveNext())
                {
                    isStartEndPeriod = true;
                }

                XdmAtomicValue result = new XdmAtomicValue(isStartEndPeriod);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:is-forever-period($period as element(xbrli:period)) as xs:boolean
    //Parameters
    //$period
    //The period.
    //Returns true if the period contains a forever element, and returns false otherwise.

    public class IsForeverPeriodXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "is-forever-period"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IsForeverPeriodXfiCall();
        }
    }

    public class IsForeverPeriodXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            bool isForeverPeriod = false;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode period = (XdmNode)arguments[0].Current;

                IEnumerator forever = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "forever"));

                if (forever.MoveNext())
                {
                    isForeverPeriod = true;
                }

                XdmAtomicValue result = new XdmAtomicValue(isForeverPeriod);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:is-duration-period($period as element(xbrli:period)) as xs:boolean
    //Parameters
    //$period
    //The period.
    //Returns true if the period is a duration period (start/end or forever).

    public class IsDurationPeriodXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "is-duration-period"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IsDurationPeriodXfiCall();
        }
    }

    public class IsDurationPeriodXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            bool isDurationPeriod = false;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode period = (XdmNode)arguments[0].Current;

                IEnumerator startDate = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "startDate"));

                IEnumerator endDate = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "endDate"));

                IEnumerator forever = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "forever"));

                if ((startDate.MoveNext() && endDate.MoveNext()) || forever.MoveNext())
                {
                    isDurationPeriod = true;
                }

                XdmAtomicValue result = new XdmAtomicValue(isDurationPeriod);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:is-instant-period($period as element(xbrli:period)) as xs:boolean
    //Parameters
    //$period
    //The period.
    //Returns true if the period is an instant period.

    public class IsInstantPeriodXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "is-instant-period"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IsInstantPeriodXfiCall();
        }
    }

    public class IsInstantPeriodXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            bool isInstantPeriod = false;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode period = (XdmNode)arguments[0].Current;

                IEnumerator instant = period.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "instant"));

                if (instant.MoveNext())
                {
                    isInstantPeriod = true;
                }

                XdmAtomicValue result = new XdmAtomicValue(isInstantPeriod);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:period-start($period as element(xbrli:period)) as xs:dateTime
    //For the dates, XBRL uses a union of date and dateTime. When a date is specified, it should be expanded to a dateTime as specified in Section 4.7.2 
    //of the XBRL specification.  Note that this expansion differs for beginning and period ends.
    //Parameters
    //$period
    //The period.
    //Return The period start dateTime for start-end periods (satisfying xfi:is-start-end-period($period) ), the instant for instants 
    //(satisfying xfi:is-instant-period($period) ), or xfie:PeriodIsForever is raised (if xfi:is-forever-period($period)).

    public class PeriodStartXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "period-start"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAnyItemType.Instance, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new PeriodStartXfiCall();
        }
    }

    public class PeriodStartXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string periodResult = null;

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode nodePeriod = (XdmNode)arguments[0].Current;

                IEnumerator dates = nodePeriod.EnumerateAxis(XdmAxis.Child);

                while (dates.MoveNext())
                {
                    XdmNode currentDate = (XdmNode)dates.Current;

                    if (currentDate.NodeKind == XmlNodeType.Element)
                    {
                        string elementName = currentDate.NodeName.LocalName;

                        if (elementName.Equals("startDate") || elementName.Equals("instant"))
                        {
                            periodResult = currentDate.StringValue;
                            break;
                        }
                    }
                }

                if (periodResult == null)
                {
                    throw new XfiException("error xfie:PeriodIsForever");
                }

                XdmAtomicValue result = null;
                Processor processor = new Processor();
                DateTime resultDateTime;
                if (DateTime.TryParse(periodResult, out resultDateTime))
                {
                    result = new XdmAtomicValue(resultDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), new QName(Constants.XS, "dateTime"), processor);
                }
                else
                {

                }

                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:period-end($period as element(xbrli:period)) as xs:dateTime
    //Parameters
    //$period
    //The period
    //Return the period end dateTime for start-end periods, the instant for instants, and the dynamic error xfie:PeriodIsForever for forever periods. 
    //If the value in the instance is just an xs:date (so not an xs:dateTime) 
    //the returning value is augmented in one day to represent the last instant of that period.

    public class PeriodEndXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "period-end"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAnyItemType.Instance, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new PeriodEndXfiCall();
        }
    }

    public class PeriodEndXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string periodResult = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode nodePeriod = (XdmNode)arguments[0].Current;

                IEnumerator dates = nodePeriod.EnumerateAxis(XdmAxis.Child);

                while (dates.MoveNext())
                {
                    XdmNode currentDate = (XdmNode)dates.Current;

                    if (currentDate.NodeKind == XmlNodeType.Element)
                    {
                        string elementName = currentDate.NodeName.LocalName;

                        if (elementName.Equals("endDate") || elementName.Equals("instant"))
                        {                            
                            periodResult = currentDate.StringValue;
                            break;
                        }
                    }
                }

                if (periodResult == null)
                {
                    throw new XfiException("error xfie:PeriodIsForever");
                }

                XdmAtomicValue result = null;
                Processor processor = new Processor();
                DateTime resultDateTime;
                if (DateTime.TryParse(periodResult, out resultDateTime))
                {
                    result = new XdmAtomicValue(resultDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), new QName(Constants.XS, "dateTime"), processor);
                }
                else
                {

                }

                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:period-instant($period as element(xbrli:period)) as xs:dateTime
    //Parameters
    //$period
    //The period,
    //Returns the period instant date-time or the dynamic error xfie:PeriodIsNotInstant is raised if period is not instant.

    public class PeriodInstantXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "period-instant"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAnyItemType.Instance, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new PeriodInstantXfiCall();
        }
    }

    public class PeriodInstantXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string periodInstant = null;

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode nodePeriod = (XdmNode)arguments[0].Current;

                IEnumerator instant = nodePeriod.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "instant"));

                if (instant == null)
                {
                    throw new XfiException("error xfie:PeriodIsNotInstant");
                }

                while (instant.MoveNext())
                {
                    XdmNode currentInstant = (XdmNode)instant.Current;
                    periodInstant = currentInstant.StringValue;
                    break;
                }

                XdmAtomicValue result = null;
                Processor processor = new Processor();
                DateTime resultDateTime;

                if (DateTime.TryParse(periodInstant, out resultDateTime))
                {
                    result = new XdmAtomicValue(resultDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), new QName(Constants.XS, "dateTime"), processor);
                }
                else
                {

                }

                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    // ===============================  Segments and Entities =================================================

    //xfi:entity($item as schema-element(xbrli:item)) as element(xbrli:entity)
    //Parameters
    //$item
    //The item.
    //Returns the entity of the context of the given item.

    public class EntityXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "entity"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new EntityXfiCall();
        }
    }

    public class EntityXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode entity = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;
                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator contexts = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode item = (XdmNode)contexts.Current;

                    IEnumerator attrs = item.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                IEnumerator entityElements = item.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "entity"));

                                while (entityElements.MoveNext())
                                {
                                    entity = (XdmNode)entityElements.Current;
                                    break;
                                }

                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)entity.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:context-entity($context as element(xbrli:context)) as element(xbrli:entity)
    //Parameters
    //$context
    //The context.
    //Returns the entity of the context.

    public class ContextEntityXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "context-entity"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ContextEntityXfiCall();
        }
    }

    public class ContextEntityXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode entity = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode contextNode = (XdmNode)arguments[0].Current;                

                IEnumerator contexts = contextNode.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;
                    
                    IEnumerator entities = currentContext.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "entity"));

                    while (entities.MoveNext())
                    {
                        entity = (XdmNode)entities.Current;
                        break;
                    }
                }

                IXdmEnumerator result = (IXdmEnumerator)entity.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:identifier($item as schema-element(xbrli:item)) as element(xbrli:identifier)
    //Parameters
    //$item
    //The item.
    //Returns the identifier element associated with the given item.

    public class IdentifierXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "identifier"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IdentifierXfiCall();
        }
    }

    public class IdentifierXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode identifier = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;

                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator contexts = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;

                    IEnumerator attrs = currentContext.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                IEnumerator identifierElements = currentContext.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLI, "identifier"));

                                while (identifierElements.MoveNext())
                                {
                                    identifier = (XdmNode)identifierElements.Current;
                                    break;
                                }

                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)identifier.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:context-identifier($context as element(xbrli:context)) as element(xbrli:identifier)
    //Parameters
    //$context
    //The context.
    //Returns the identifier element associated with the given context.

    public class ContextIdentifierXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "context-identifier"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ContextIdentifierXfiCall();
        }
    }

    public class ContextIdentifierXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode identifier = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode contextNode = (XdmNode)arguments[0].Current;

                IEnumerator contexts = contextNode.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;

                    IEnumerator entities = currentContext.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLI, "identifier"));

                    while (entities.MoveNext())
                    {
                        identifier = (XdmNode)entities.Current;
                        break;
                    }
                }

                IXdmEnumerator result = (IXdmEnumerator)identifier.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:entity-identifier($entity as element(xbrli:entity)) as element(xbrli:identifier)
    //Parameters
    //$entity
    //The entity.
    //Returns the identifier element associated with the given entity.

    public class EntityIdentifierXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "entity-identifier"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new EntityIdentifierXfiCall();
        }
    }

    public class EntityIdentifierXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode identifier = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode entityNode = (XdmNode)arguments[0].Current;

                IEnumerator identifiers = entityNode.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "identifier"));

                while (identifiers.MoveNext())
                {
                    identifier = (XdmNode)identifiers.Current;                    
                }

                IXdmEnumerator result = (IXdmEnumerator)identifier.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:identifier-value($identifier as element(xbrli:identifier)) as xs:token
    //Parameters
    //$identifier
    //The identifier.
    //Returns the value of the identifier token.

    public class IdentifierValueXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "identifier-value"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IdentifierValueXfiCall();
        }
    }

    public class IdentifierValueXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string value = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode identifierNode = (XdmNode)arguments[0].Current;

                value = identifierNode.StringValue;

                XdmAtomicValue result = new XdmAtomicValue(value);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:identifier-scheme($identifier as element(xbrli:identifier)) as xs:anyURI
    //Parameters
    //$identifier
    //The identifier.
    //Return the value of the scheme attribute of the identifier of the entity.

    public class IdentifierSchemeXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "identifier-scheme"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IdentifierSchemeXfiCall();
        }
    }

    public class IdentifierSchemeXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string scheme = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode identifierNode = (XdmNode)arguments[0].Current;

                IEnumerator attrs = identifierNode.EnumerateAxis(XdmAxis.Attribute);

                while (attrs.MoveNext())
                {
                    XdmNode attr = (XdmNode)attrs.Current;

                    string attributeName = attr.NodeName.LocalName;

                    if (attributeName.Equals("scheme"))
                    {
                        scheme = attr.StringValue;
                    }
                }
                
                XdmAtomicValue result = new XdmAtomicValue(scheme);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:segment($item as schema-element(xbrli:item)) as element(xbrli:segment)?
    //Parameters
    //$item
    //The item.
    //Return the segment of the given item if present and an empty sequence otherwise.

    public class SegmentXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "segment"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new SegmentXfiCall();
        }
    }

    public class SegmentXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode segment = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;
                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator contexts = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;

                    IEnumerator attrs = currentContext.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                IEnumerator segmentElements = currentContext.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLI, "segment"));

                                while (segmentElements.MoveNext())
                                {
                                    segment = (XdmNode)segmentElements.Current;
                                    break;
                                }

                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)segment.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:entity-segment($entity as element(xbrli:entity)) as element(xbrli:segment)?
    //Parameters
    //$entity
    //The entity containing the segment.
    //Return the segment content of the given entity if present and an empty sequence otherwise.

    public class EntitySegmentXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "entity-segment"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new EntitySegmentXfiCall();
        }
    }

    public class EntitySegmentXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode segment = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode entityNode = (XdmNode)arguments[0].Current;

                IEnumerator segments = entityNode.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "segment"));

                while (segments.MoveNext())
                {
                    segment = (XdmNode)segments.Current;
                }

                IXdmEnumerator result = (IXdmEnumerator)segment.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:context-segment($context as element(xbrli:context)) as element(xbrli:segment)?
    //Parameters
    //$context
    //The context.
    //Return the segment content of the given context if present and an empty sequence otherwise.

    public class ContextSegmentXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "context-segment"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ContextSegmentXfiCall();
        }
    }

    public class ContextSegmentXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode segment = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode contextNode = (XdmNode)arguments[0].Current;

                IEnumerator segments = contextNode.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLI, "segment"));

                while (segments.MoveNext())
                {
                    segment = (XdmNode)segments.Current;
                }

                IXdmEnumerator result = (IXdmEnumerator)segment.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:scenario($item as schema-element(xbrli:item)) as element(xbrli:scenario)? 
    //Parameters
    //$item
    //The item.
    //Return the scenario of the given item if present and an empty sequence otherwise.

    public class ScenarioXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "scenario"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ScenarioXfiCall();
        }
    }

    public class ScenarioXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode scenario = new XdmNode();

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;
                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode contextItem = (XdmNode)context.ContextItem;

                IEnumerator contexts = contextItem.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;

                    IEnumerator attrs = currentContext.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                IEnumerator scenarioElements = currentContext.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLI, "scenario"));

                                while (scenarioElements.MoveNext())
                                {
                                    scenario = (XdmNode)scenarioElements.Current;
                                    break;
                                }

                                break;
                            }
                        }
                    }

                }

                IXdmEnumerator result = (IXdmEnumerator)scenario.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:context-scenario($context as element(xbrli:context)) as element(xbrli:scenario)?
    //Parameters
    //$context
    //The context.
    //Return the scenario content of the given context if present and an empty sequence otherwise.

    public class ContextScenarioXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "context-scenario"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ContextScenarioXfiCall();
        }
    }

    public class ContextScenarioXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode scenario = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            if (exists)
            {
                XdmNode contextNode = (XdmNode)arguments[0].Current;

                IEnumerator scenarios = contextNode.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLI, "scenario"));

                while (scenarios.MoveNext())
                {
                    scenario = (XdmNode)scenarios.Current;                    
                }

                IXdmEnumerator result = (IXdmEnumerator)scenario.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    // =============================== Facts and tuples ===========================================


    //xfi:items-in-instance($instance as element(xbrli:xbrl)) as schema-element(xbrli:item)*
    //Parameters
    //$instance
    //Instance document
    //Return a sequence of facts that are direct children of the main xbrli:xbrl element.

    public class ItemsInInstanceXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "items-in-instance"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ItemsInInstanceXfiCall();
        }
    }

    public class ItemsInInstanceXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmValue items = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode instance = (XdmNode)arguments[0].Current;

                IEnumerator childrenNode = instance.EnumerateAxis(XdmAxis.Child);

                ArrayList list = new ArrayList();

                while (childrenNode.MoveNext())
                {
                    XdmNode currentChild = (XdmNode)childrenNode.Current;

                    if (currentChild.NodeKind == XmlNodeType.Element)
                    {
                        IEnumerator contextRef = currentChild.EnumerateAxis(XdmAxis.Attribute, new QName(Constants.XBRLI, "contextRef"));

                        if (contextRef.MoveNext())
                        {
                            list.Add(currentChild);
                        }
                    }
                }

                items = new XdmValue(list);

                IXdmEnumerator result = (IXdmEnumerator)items.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:tuples-in-instance($instance as element(xbrli:xbrl)) as schema-element(xbrli:tuple)*
    //Parameters
    //$instance
    //Instance document
    //Return a sequence of tuples that are direct children of the main xbrli:xbrl element.

    public class TuplesInInstanceXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "tuples-in-instance"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new TuplesInInstanceXfiCall();
        }
    }

    public class TuplesInInstanceXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmValue tuples = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode instance = (XdmNode)arguments[0].Current;

                IEnumerator childrenNode = instance.EnumerateAxis(XdmAxis.Child);

                ArrayList list = new ArrayList();

                while (childrenNode.MoveNext())
                {
                    XdmNode currentChild = (XdmNode)childrenNode.Current;

                    if (currentChild.NodeKind == XmlNodeType.Element)
                    {
                        IEnumerator contextRef = currentChild.EnumerateAxis(XdmAxis.Attribute, new QName(Constants.XBRLI, "contextRef"));

                        if (!contextRef.MoveNext() &&
                            !currentChild.NodeName.ToXmlQualifiedName().Namespace.Equals(Constants.XBRLI) &&
                            !currentChild.NodeName.ToXmlQualifiedName().Namespace.Equals(Constants.LINK))
                        {
                            list.Add(currentChild);
                        }
                    }
                }

                tuples = new XdmValue(list);

                IXdmEnumerator result = (IXdmEnumerator)tuples.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:items-in-tuple($tuple as schema-element(xbrli:tuple)) as schema-element(xbrli:item)*
    //Parameters
    //$tuple
    //Container tuple
    //Return a sequence of facts that are direct children of the $tuple element.

    public class ItemsInTupleXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "items-in-tuple"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new ItemsInTupleXfiCall();
        }
    }

    public class ItemsInTupleXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmValue items = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode tuple = (XdmNode)arguments[0].Current;

                IEnumerator childrenNode = tuple.EnumerateAxis(XdmAxis.Child);

                ArrayList list = new ArrayList();

                while (childrenNode.MoveNext())
                {
                    XdmNode currentChild = (XdmNode)childrenNode.Current;

                    if (currentChild.NodeKind == XmlNodeType.Element)
                    {
                        IEnumerator contextRef = tuple.EnumerateAxis(XdmAxis.Attribute, new QName(Constants.XBRLI, "contextRef"));

                        if (contextRef.MoveNext())
                        {
                            list.Add(currentChild);
                        }
                    }
                }

                items = new XdmValue(list);

                IXdmEnumerator result = (IXdmEnumerator)items.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:tuples-in-tuple($tuple as schema-element(xbrli:tuple)) as schema-element(xbrli:tuple)*
    //Parameters
    //$tuple
    //Container tuple
    //Return a sequence of tuples that are children of the $tuple parameter.

    public class TuplesInTupleXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "tuples-in-tuple"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmNodeKind.Element, '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new TuplesInTupleXfiCall();
        }
    }

    public class TuplesInTupleXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmValue tuples = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmNode tuple = (XdmNode)arguments[0].Current;

                IEnumerator childrenNode = tuple.EnumerateAxis(XdmAxis.Child);

                ArrayList list = new ArrayList();

                while (childrenNode.MoveNext())
                {
                    XdmNode currentChild = (XdmNode)childrenNode.Current;

                    if (currentChild.NodeKind == XmlNodeType.Element)
                    {
                        IEnumerator contextRef = tuple.EnumerateAxis(XdmAxis.Attribute, new QName(Constants.XBRLI, "contextRef"));

                        if (!contextRef.MoveNext())
                        {
                            list.Add(currentChild);
                        }
                    }
                }

                tuples = new XdmValue(list);

                IXdmEnumerator result = (IXdmEnumerator)tuples.GetEnumerator();
                return result;
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    // ======================================== Predicates ==================================================


    //xfi:identical-nodes($left as node()*, $right as node()*) as xs:boolean
    //Parameters
    //$left  The first node to compare.
    //$right  The second node to compare.
    //Return the value as an xs:boolean of evaluating the identical node comparison on the list of node lists (or individual nodes).

    public class IdenticalNodesXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "identical-nodes"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '*')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new IdenticalNodesXfiCall();
        }
    }

    public class IdenticalNodesXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmAtomicValue result = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmValue left = (XdmValue)arguments[0].Current;

                XdmValue right = (XdmValue)arguments[1].Current;

                if (left.Count != right.Count)
                {
                    result = new XdmAtomicValue(false);
                    return (IXdmEnumerator)result.GetEnumerator();
                }

                //for (var i = 0; i < left.Count; i++)
                //{
                //    if (left.GetList()[i].Equals(right.GetList()[i]))
                //    {
                //        result = new XdmAtomicValue(false);
                //        return (IXdmEnumerator)result.GetEnumerator();
                //    }
                //}

                foreach (XdmItem item in left.GetList())
                {
                    if (!right.GetList().Contains(item))
                    {
                        result = new XdmAtomicValue(false);
                        return (IXdmEnumerator)result.GetEnumerator();
                    }
                }

                result = new XdmAtomicValue(true);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }


    //xfi:s-equal($left as node()*, $right as node()*) as xs:boolean
    //Parameters
    //$left   The first node to compare.
    //$right  The second node to compare.
    //Return the value as an xs:boolean of evaluating the s-equal predicate on the list of node lists (or individual nodes).

    public class SEqualXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "s-equal"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 2; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new SEqualXfiCall();
        }
    }


    public class SEqualXfiCall : ExtensionFunctionCall

    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmAtomicValue result = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmValue left = (XdmValue)arguments[0].Current;

                XdmValue right = (XdmValue)arguments[1].Current;

                if (left.Count != right.Count)
                {
                    result = new XdmAtomicValue(false);
                    return (IXdmEnumerator)result.GetEnumerator();
                }

                if (!EqualXdmValues(left, right))
                {
                    result = new XdmAtomicValue(false);
                    return (IXdmEnumerator)result.GetEnumerator();
                }

                result = new XdmAtomicValue(true);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }

        private bool EqualXdmValues(XdmValue left, XdmValue right)
        {
            for (var i = 0; i < left.Count; i++)
            {
                if (!SEqual((XdmItem)left.GetList()[i], (XdmItem)right.GetList()[i]))
                {
                    return false;
                }
            }

            return true;
        }

        private bool SEqual(XdmItem item1, XdmItem item2)
        {
            XdmNode nodeA = null;
            XdmNode nodeB = null;

            if ((item1.IsAtomic() && !item2.IsAtomic()) || (!item1.IsAtomic() && item2.IsAtomic()))
            {
                return false;
            }

            if (item1.IsAtomic() && item2.IsAtomic())
            {
                ValueRepresentation vr1 = item1.Unwrap();
                ValueRepresentation vr2 = item1.Unwrap();

                if (!vr1.Equals(vr2))
                {
                    return false;
                }
            }

            if (!item1.IsAtomic() && !item2.IsAtomic())            
            {
                nodeA = (XdmNode)item1.Simplify;
                nodeB = (XdmNode)item2.Simplify;

                XmlNamespaceManager mngr = new XmlNamespaceManager(new NameTable());
                mngr.AddNamespace(nodeA.NodeName.Prefix, "");

                XElement e1 = ParseElement(nodeA.OuterXml, mngr);
                XElement e2 = XElement.Parse(nodeA.OuterXml);

                if (!XNode.DeepEquals(e1,e2))
                {
                    return false;
                }
            }
            
            return true;
        }

        public static XElement ParseElement(string strXml, XmlNamespaceManager mngr)
        {
            XmlParserContext parserContext = new XmlParserContext(null, mngr, null, XmlSpace.None);
            XmlTextReader txtReader = new XmlTextReader(strXml, XmlNodeType.Element, parserContext);
            return XElement.Load(txtReader);
        }
    }


    public class UEqualXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "u-equal"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 1; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new UEqualXfiCall();
        }
    }


    public class UEqualXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmAtomicValue result = null;

            Boolean exists = arguments[0].MoveNext();

            if (exists)
            {
                XdmValue left = (XdmValue)arguments[0].Current;

                XdmValue right = (XdmValue)arguments[1].Current;

                if (left.Count != right.Count)
                {
                    result = new XdmAtomicValue(false);
                    return (IXdmEnumerator)result.GetEnumerator();
                }

                for (var i = 0; i < left.Count; i++)
                {
                    XdmItem item1 = (XdmItem)left.GetList()[i];
                    XdmItem item2 = (XdmItem)right.GetList()[i];

                    if (UEqual(item1, item2, context))
                    {
                        result = new XdmAtomicValue(false);
                        return (IXdmEnumerator)result.GetEnumerator();
                    }
                }

                result = new XdmAtomicValue(true);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }


        private bool UEqual(XdmItem item1, XdmItem item2, DynamicContext context)
        {
            XdmNode nodeA = null;
            XdmNode nodeB = null;
            XdmNode unit1 = null;
            XdmNode unit2 = null;

            if ((item1.IsAtomic() && !item2.IsAtomic()) || (!item1.IsAtomic() && item2.IsAtomic()))
            {
                return false;
            }

            if (item1.IsAtomic() && item2.IsAtomic())
            {
                ValueRepresentation vr1 = item1.Unwrap();
                ValueRepresentation vr2 = item1.Unwrap();

                if (!vr1.Equals(vr2))
                {
                    return false;
                }
            }

            if (!item1.IsAtomic() && !item2.IsAtomic())
            {
                nodeA = (XdmNode)item1.Simplify;
                nodeB = (XdmNode)item2.Simplify;

                unit1 = GetUnit(context, nodeA);
                unit2 = GetUnit(context, nodeA);

                XmlNamespaceManager mngr = new XmlNamespaceManager(new NameTable());
                mngr.AddNamespace(nodeA.NodeName.Prefix, "");

                XElement e1 = ParseElement(unit1.OuterXml, mngr);
                XElement e2 = XElement.Parse(unit2.OuterXml);

                if (!XNode.DeepEquals(e1, e2))
                {
                    return false;
                }
            }

            return true;
        }

        private static XdmNode GetUnit(DynamicContext context, XdmNode nodeA)
        {
            IEnumerator unitRefA = nodeA.EnumerateAxis(XdmAxis.Attribute, new QName(Constants.XBRLI, "unitRef"));

            string unitRef = "";

            while (unitRefA.MoveNext())
            {
                XdmNode currentAttr = (XdmNode)unitRefA.Current;

                if (currentAttr.NodeKind == XmlNodeType.Attribute)
                {
                    string attributeName = currentAttr.NodeName.LocalName;
                    if (attributeName.Equals("unitRef"))
                    {
                        unitRef = currentAttr.StringValue;
                        break;
                    }
                }
            }

            XdmNode xbrl = (XdmNode)context.ContextItem;

            IEnumerator units = xbrl.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "unit"));

            while (units.MoveNext())
            {
                XdmNode currentUnit = (XdmNode)units.Current;

                IEnumerator attrs = currentUnit.EnumerateAxis(XdmAxis.Attribute);

                while (attrs.MoveNext())
                {
                    XdmNode attr = (XdmNode)attrs.Current;

                    string attributeName = attr.NodeName.LocalName;

                    if (attributeName.Equals("id"))
                    {
                        if (attr.StringValue == unitRef)
                        {
                            return currentUnit;
                        }
                    }
                }

            }
            return null;
        }

        public static XElement ParseElement(string strXml, XmlNamespaceManager mngr)
        {
            XmlParserContext parserContext = new XmlParserContext(null, mngr, null, XmlSpace.None);
            XmlTextReader txtReader = new XmlTextReader(strXml, XmlNodeType.Element, parserContext);
            return XElement.Load(txtReader);
        }
    }


    //Returns the QName of the value for the dimension that is reported in the segment or scenario of the item.
    //If the dimension is not reported for the item and no default is applicable, this function returns an empty sequence.
    //This function reports the dimension default value when applicable.

    public class FactExplicitDimensionValueXfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "fact-explicit-dimension-value"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 2; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?'), new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_QNAME), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new FactExplicitDimensionValueXfiCall();
        }
    }


    public class FactExplicitDimensionValueXfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            string dimensionValue = null;

            XdmNode explicitDimension = new XdmNode();

            Boolean exists = arguments[0].MoveNext();
            Boolean exists2 = arguments[1].MoveNext();
            XdmValue dimensionX = (XdmValue)arguments[1].Current;
            string dimension = dimensionX.ToString();

            if (exists)
            {
                XdmNode nodeItem = (XdmNode)arguments[0].Current;

                IEnumerator attributes = nodeItem.EnumerateAxis(XdmAxis.Attribute);

                string contextRef = "";

                while (attributes.MoveNext())
                {
                    XdmNode currentAttr = (XdmNode)attributes.Current;

                    if (currentAttr.NodeKind == XmlNodeType.Attribute)
                    {
                        string attributeName = currentAttr.NodeName.LocalName;

                        if (attributeName.Equals("contextRef"))
                        {
                            contextRef = currentAttr.StringValue;
                            break;
                        }
                    }
                }

                XdmNode xbrl = (XdmNode)context.ContextItem;

                IEnumerator contexts = xbrl.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));

                IEnumerator explicitDimensionElements = null;

                while (contexts.MoveNext())
                {
                    XdmNode currentContext = (XdmNode)contexts.Current;

                    IEnumerator attrs = currentContext.EnumerateAxis(XdmAxis.Attribute);

                    while (attrs.MoveNext())
                    {
                        XdmNode attr = (XdmNode)attrs.Current;

                        string attributeName = attr.NodeName.LocalName;

                        if (attributeName.Equals("id"))
                        {
                            if (attr.StringValue == contextRef)
                            {
                                explicitDimensionElements = currentContext.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLDI, "explicitMember"));
                                goto next;
                            }
                        }
                    }
                }

            next: ;
                while (explicitDimensionElements != null && explicitDimensionElements.MoveNext())
                {
                    explicitDimension = (XdmNode)explicitDimensionElements.Current;

                    IEnumerator attrsDimension = explicitDimension.EnumerateAxis(XdmAxis.Attribute);

                    while (attrsDimension.MoveNext())
                    {
                        XdmNode attrDimension = (XdmNode)attrsDimension.Current;

                        string dimensionName = attrDimension.NodeName.LocalName;

                        if (dimensionName.Equals("dimension"))
                        {
                            if (attrDimension.StringValue == dimension)
                            {
                                dimensionValue = explicitDimension.StringValue;
                                break;
                            }
                        }
                    }
                }

                XdmAtomicValue result = new XdmAtomicValue(dimensionValue);
                return (IXdmEnumerator)result.GetEnumerator();
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }
    }

    // This function compares two items in the specified dimension (may be segment or scenario) and 
    // returns true if the specified items are s-equal in the instance document(s).
    // xfi:fact-dimension-s-equal2($left as xbrli:item, $right as xbrli:item, $dimension as xs:QName) as xs:boolean

    public class FactDimensionSequal2Xfi : ExtensionFunctionDefinition
    {

        public override QName FunctionName
        {
            get { return new QName("http://www.xbrl.org/2008/function/instance", "fact-dimension-s-equal2"); }
        }

        public override int MinimumNumberOfArguments
        {
            get { return 1; }
        }

        public override int MaximumNumberOfArguments
        {
            get { return 3; }
        }

        public override XdmSequenceType[] ArgumentTypes
        {
            get
            {
                return new XdmSequenceType[] {
                    new XdmSequenceType(XdmNodeKind.Element, '?'), 
                    new XdmSequenceType(XdmNodeKind.Element, '?'), 
                    new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_QNAME), '?')
                    };
            }
        }

        public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
        {
            return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_BOOLEAN), '?');
        }

        public override bool TrustResultType
        {
            get { return true; }
        }

        public override ExtensionFunctionCall MakeFunctionCall()
        {
            return new FactDimensionSequal2XfiCall();
        }
    }


    public class FactDimensionSequal2XfiCall : ExtensionFunctionCall
    {

        public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context)
        {
            XdmNode explicitDimension1;
            XdmNode explicitDimension2;

            Boolean exists = arguments[0].MoveNext();
            Boolean exists2 = arguments[1].MoveNext();

            Boolean exists3 = arguments[2].MoveNext();
            XdmValue dimensionX = (XdmValue)arguments[2].Current;
            string dimension = dimensionX.ToString();

            if (exists)
            {
                XdmNode item1 = (XdmNode)arguments[0].Current;

                XdmNode contextItem1 = null;
                XdmNode contextItem2 = null;

                contextItem1 = GetContextOfItem(context, item1);

                IEnumerator explicitDimensionElements = contextItem1.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLDI, "explicitMember"));

                explicitDimension1 = GetDimension(dimension, explicitDimensionElements);

                XdmNode item2 = (XdmNode)arguments[1].Current;

                contextItem2 = GetContextOfItem(context, item2);

                explicitDimensionElements = contextItem2.EnumerateAxis(XdmAxis.Descendant, new QName(Constants.XBRLDI, "explicitMember"));

                explicitDimension2 = GetDimension(dimension, explicitDimensionElements);

                if (explicitDimension1 != null && explicitDimension2 != null)
                {
                    if (explicitDimension1.StringValue == explicitDimension2.StringValue)
                    {
                        XdmAtomicValue result = new XdmAtomicValue(true);
                        return (IXdmEnumerator)result.GetEnumerator();
                    }
                    else
                    {
                        XdmAtomicValue result = new XdmAtomicValue(false);
                        return (IXdmEnumerator)result.GetEnumerator();
                    }
                }
                else
                {
                    XdmAtomicValue result = new XdmAtomicValue(false);
                    return (IXdmEnumerator)result.GetEnumerator();
                }
            }
            else
            {
                return EmptyEnumerator.INSTANCE;
            }
        }


        private static XdmNode GetDimension(string dimension, IEnumerator explicitDimensionElements)
        {
            while (explicitDimensionElements != null && explicitDimensionElements.MoveNext())
            {
                XdmNode explicitDimension = (XdmNode)explicitDimensionElements.Current;

                IEnumerator attrsDimension = explicitDimension.EnumerateAxis(XdmAxis.Attribute);

                while (attrsDimension.MoveNext())
                {
                    XdmNode attrDimension = (XdmNode)attrsDimension.Current;

                    string dimensionName = attrDimension.NodeName.LocalName;

                    if (dimensionName.Equals("dimension"))
                    {
                        if (attrDimension.StringValue == dimension)
                        {
                            return explicitDimension;
                        }
                    }
                }
            }

            return null;
        }


        private XdmNode GetContextOfItem(DynamicContext context, XdmNode item1)
        {
            IEnumerator attributes = item1.EnumerateAxis(XdmAxis.Attribute);

            string contextRef = "";

            while (attributes.MoveNext())
            {
                XdmNode currentAttr = (XdmNode)attributes.Current;

                if (currentAttr.NodeKind == XmlNodeType.Attribute)
                {
                    string attributeName = currentAttr.NodeName.LocalName;

                    if (attributeName.Equals("contextRef"))
                    {
                        contextRef = currentAttr.StringValue;
                        break;
                    }
                }
            }

            XdmNode xbrl = (XdmNode)context.ContextItem;

            IEnumerator contexts = xbrl.EnumerateAxis(XdmAxis.Child, new QName(Constants.XBRLI, "context"));            

            while (contexts.MoveNext())
            {
                XdmNode currentContext = (XdmNode)contexts.Current;

                IEnumerator attrs = currentContext.EnumerateAxis(XdmAxis.Attribute);

                while (attrs.MoveNext())
                {
                    XdmNode attr = (XdmNode)attrs.Current;

                    if (attr.NodeName.LocalName.Equals("id"))
                    {
                        if (attr.StringValue == contextRef)
                        {
                            return currentContext;                            
                        }
                    }
                }
            }

            return null;
        }


        private bool SEqual(XdmItem item1, XdmItem item2)
        {
            XdmNode nodeA = null;
            XdmNode nodeB = null;

            if ((item1.IsAtomic() && !item2.IsAtomic()) || (!item1.IsAtomic() && item2.IsAtomic()))
            {
                return false;
            }

            if (item1.IsAtomic() && item2.IsAtomic())
            {
                ValueRepresentation vr1 = item1.Unwrap();
                ValueRepresentation vr2 = item1.Unwrap();

                if (!vr1.Equals(vr2))
                {
                    return false;
                }
            }

            if (!item1.IsAtomic() && !item2.IsAtomic())
            {
                nodeA = (XdmNode)item1.Simplify;
                nodeB = (XdmNode)item2.Simplify;

                XmlNamespaceManager mngr = new XmlNamespaceManager(new NameTable());
                mngr.AddNamespace(nodeA.NodeName.Prefix, "");

                XElement e1 = ParseElement(nodeA.OuterXml, mngr);
                XElement e2 = XElement.Parse(nodeA.OuterXml);

                if (!XNode.DeepEquals(e1, e2))
                {
                    return false;
                }
            }

            return true;
        }


        public static XElement ParseElement(string strXml, XmlNamespaceManager mngr)
        {
            XmlParserContext parserContext = new XmlParserContext(null, mngr, null, XmlSpace.None);
            XmlTextReader txtReader = new XmlTextReader(strXml, XmlNodeType.Element, parserContext);
            return XElement.Load(txtReader);
        }
    }
}
